home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
422_02
/
misc
/
mdcfs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-20
|
23KB
|
811 lines
/*
* MDCFS: Minimal Dos Compatible File System
*
* These routines provide the bare minimum needed to read and write
* files on an MS-DOS format floppy disk. You could use them with a hard
* disk as well, however since only 12 bit FAT's are supported, you are
* limited to a total of 4096 clusters, and total drive space is limited
* to 32MB due to 16 bit sector numbers (assuming 512 byte sectors).
*
* The functions were written for use in embedded systems (where memory
* is often limited), and therefore provide only the basic open, read/write,
* close and delete operations. I have documented the functions which
* manipulate the directory and FAT, and it should be fairly easy to add
* other features if you need them (directory display etc.). Only access to
* files in the ROOT directory is provided, subdirectories are NOT supported.
*
* For simplicity and memory conservation, these functions buffer only 1
* sector (512 bytes) in memory. This makes them run quite slowly, but is
* adaquate for reading/writing setup information and occational data logging.
* If you have lots of memory and need extra speed, you could modify the
* functions to read/write multiple sectors (a cluster would be easy).
* You can also experiment with different interleave factors, to obtain
* optimim performance with the existing I/O functions.
*
* As they stand, the functions really support access to only one drive
* at a time. You can use multiple drives if you call "open_drive()" between
* disk operations to the separate drives. This "switches" the active drive
* to the specified one. Note however, that the selected drive will seek to
* track zero each time this function is called, so performing many small
* operations on more than one drive gets VERY inefficent. DO NOT read or
* write to an open file located on any drive other than the currently
* selected one! Call "open_drive()" first!
*
* Concurrent access to multiple files (on the same drive) is supported,
* however since only one "work" buffer is used for directory/FAT access,
* the drive may have to perform extra read/write operation when switching
* from one file to the other. For this reason, it is best to try and do
* as many reads or writes as possible on one file before accessing others.
* Avoid many small operations to multiple files.
*
* At present, only the first copy of the disk File Allocation Table
* (FAT) is used by these functions.
*
* Functions read/write data in RAW (binary) form, without regard for
* NEWLINE characters etc. If you want to read/write ASCII text, you will
* have to write "wrapper" functions to drop RETURN (0x0D) characters on
* reading, and to add them before NEWLINE (0x0A) when writing.
*
* Due to the use of 'C' structures, Version 3.0 (or later) of MICRO-C
* is REQUIRED! It should not be difficult to compile with a different
* compiler, but I have not attempted to do so.
*
* Copyright 1993-1994 Dave Dunfield
* All rights reserved.
*
* Permission granted for personal (non-commercial) use only.
*/
/* Required definitions from MICRO-C stdio.h (not part of MDCFS) */
extern register printf();
#define FILE unsigned
/* Misc fixed parameters */
#define SECTOR_SIZE 512 /* Size of a disk sector */
#define BPB_SIZE 17 /* Number of bytes in BIOS Parm Block */
#define EMPTY 0xE5 /* Signals empty directory */
#define EOF -1 /* End of file indicator */
#define ERROR -2 /* Report error in file */
#define READ 0 /* File opened for READ */
#define WRITE 1 /* File opened for WRITE */
/*
* Structure of MSDOS directory entry
*/
struct Dentry {
unsigned char Dname[11]; /* Filename + extension */
unsigned char Dattr; /* File attributes */
unsigned char Dreserved[10]; /* Reserved area */
unsigned Dtime; /* Time last modified */
unsigned Ddata; /* Date last modified */
unsigned Dcluster; /* First cluster number */
unsigned Dsizel; /* File size (LOW) */
unsigned Dsizeh; } ; /* File size (HIGH) */
/*
* Structure of internal file control block
*/
struct Fblock {
unsigned char Fattr; /* Open attributes */
unsigned char Fsector; /* Sector within cluster */
struct Dentry *Fdirptr; /* Pointer to directory entry */
unsigned Fdirsec; /* Directory sector */
unsigned Ffirstcls; /* First cluster in file */
unsigned Flastcls; /* Last cluster read/written */
unsigned Fnextcls; /* Next cluster to read/write */
unsigned Foffset; /* Read/Write offset */
unsigned Fsizel; /* File size (LOW) */
unsigned Fsizeh; /* File size (HIGH) */
unsigned char Fbuffer[]; } ; /* Data transfer buffer */
/* Internal "work" sector variables */
unsigned wrkdrv = 0, /* Current work drive number */
wrksec = -1; /* Current work sector number */
char wrkchg = 0; /* Indicates work sector changed */
unsigned char wrkbuff[SECTOR_SIZE]; /* Work sector buffer */
/* Active drive information (other than contained in BPB) */
char active_drive = -1; /* Open disk drive number */
unsigned dirsec = 5, /* First sector of directory */
datasec = 12; /* First sector of data area */
/* Disk information (from BIOS Parameter Block) */
unsigned int bytsec = 512; /* Bytes / sector */
unsigned char seccls = 2; /* Sectors / cluster */
unsigned int ressec = 1; /* # reserved sectors */
unsigned char numfat = 2; /* Number of FAT's */
unsigned int dirent = 112; /* Number of directory entries */
unsigned int sectors = 720; /* Sectors on disk */
unsigned char mediaid = 0xFD; /* Media ID byte */
unsigned int secfat = 2; /* Sectors / fat */
unsigned int sectrk = 9; /* Sectors / track */
unsigned int numhead = 2; /* Number of heads */
/*
* Function Prototypes
*/
extern struct Dentry *lookup(), *create_file();
/*
* File accessing functions:
*
* open_drive(drive) - Initialize a drive for file access
* drive - Drive id (0=A, 1=B ...)
*
* open_file(name, attrs) - Open file for read or write
* name - Name of file to open
* attrs - Open attributes: READ or WRITE
* returns : Pointer to file structure, or 0 if failure
*
* close_file(fp) - Close an open file
* fp - Pointer to open file structure
*
* read_byte(fp) - Read a byte from an open file
* fp - Pointer to open file structure
* returns : Value read (0-255), -1 if EOF, -2 if not open for read
*
* write_byte(byte, fp) - Write a byte to a file
* byte - Value to write to file (0-255)
* returns : Value written (0-255) or -2 if error
*
* delete_file(name) - Erases the named file
* name - Name of file to erase
* returns : 0 if Success, -1 if failure (file not found)
*/
/*
* Open a disk drive and set up control information
*
* THIS FUNCTION MUST BE CALLED BEFORE ACCESSING ANY FILES,
* AND ANYTIME YOU SWITCH TO ACCESS A DIFFERENT DRIVE.
*/
open_drive(drive)
char drive;
{
read_work(active_drive = drive, 0);
memcpy(&bytsec, wrkbuff+11, BPB_SIZE);
dirsec = (numfat * secfat) + ressec;
datasec = ((((dirent * sizeof(struct Dentry)) + bytsec) - 1) / bytsec) + dirsec;
}
/*
* Open a file & return a pointer to an allocated file structure
*/
struct Fblock *open_file(name, attrs)
char *name;
int attrs;
{
struct Dentry *dirptr;
struct Fblock *fp;
if(dirptr = lookup(name)) { /* File already exists */
if(attrs == WRITE) /* Zero size on write */
dirptr->Dsizel = dirptr->Dsizeh = 0; }
else {
if(attrs != WRITE) /* Not writing file */
return 0;
if(!(dirptr = create_file(name, 0))) /* Unable to create */
return 0; }
/* Allocate buffer for file control block */
if(!(fp = malloc(bytsec+sizeof(struct Fblock))))
return 0;
/* Fill in file control block from directory information */
fp->Fdirsec = wrksec;
fp->Fdirptr = dirptr;
fp->Fattr = attrs;
fp->Fnextcls = fp->Ffirstcls = dirptr->Dcluster;
fp->Fsizel = dirptr->Dsizel;
fp->Fsizeh = dirptr->Dsizeh;
fp->Fsector = fp->Foffset = fp->Flastcls = 0;
return fp;
}
/*
* Close an open file
*/
c